﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using SouthApps.MobileHealth.SDK.DAL.Model;
using SouthApps.MobileTasks.SDK.DAL.Repositories;
using SouthApps.Framework.LoggerService;

namespace SouthApps.MobileHealth.SDK.Cache
{
    public static class LocacionesServicioEspecialCache
    {
        private static ReaderWriterLock cacheReaderWriterLock = new ReaderWriterLock();
        private static IPrestadoresRepository prestadoresRepository;
        private static Dictionary<int, List<LocacionServicioEspecial>> locacionesServicioEspecial = new Dictionary<int, List<LocacionServicioEspecial>>();
        private static bool initialized = false;
        private static object lockObject = new object();

        public static void Initialize(List<int> financiadoresId)
        {
            try
            {
                lock (lockObject)
                {
                    if (!initialized)
                    {
                        LocacionesServicioEspecialCache.prestadoresRepository = new PrestadoresRepository();
                        LocacionesServicioEspecialCache.LoadLocacionesServicioEspecialFromDatabase(financiadoresId);
                        initialized = true;
                    }
                }
            }
            catch (Exception ex)
            {
                LoggerService.Log(LogLevel.Error, "An error ocurred while initializing locaciones servicio especial cache.", ex);
                throw ex;
            }
        }

        private static void LoadLocacionesServicioEspecialFromDatabase(List<int> financiadoresId)
        {
            cacheReaderWriterLock.AcquireWriterLock(Timeout.Infinite);

            try
            {
                foreach (int financiadorId in financiadoresId)
                {
                    List<LocacionServicioEspecial> locacionServicioEspecial = LocacionesServicioEspecialCache.prestadoresRepository.GetLocacionesServiciosEspecialesFinanciador(financiadorId);
                    LocacionesServicioEspecialCache.locacionesServicioEspecial.Add(financiadorId, locacionServicioEspecial);
                }
            }
            finally
            {
                cacheReaderWriterLock.ReleaseWriterLock();
            }
        }

        public static void AddLocacionServicioEspecialToCache(int financiadorId, LocacionServicioEspecial locacionServicioEspecial)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (LocacionesServicioEspecialCache.locacionesServicioEspecial.ContainsKey(financiadorId))
            {
                List<LocacionServicioEspecial> sucursalesPrestadorList = LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId];

                cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
                sucursalesPrestadorList.Add(locacionServicioEspecial);
                LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId] = sucursalesPrestadorList;

                cacheReaderWriterLock.ReleaseLock();
            }
            else
            {
                List<LocacionServicioEspecial> sucursalesPrestadorList = new List<LocacionServicioEspecial>();
                sucursalesPrestadorList.Add(locacionServicioEspecial);

                cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
                LocacionesServicioEspecialCache.locacionesServicioEspecial.Add(financiadorId, sucursalesPrestadorList);

                cacheReaderWriterLock.ReleaseLock();
            }
        }

        public static void RemoveLocacionServicioEspecialFromCache(int financiadorId, LocacionServicioEspecial sucursalPrestador)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (!LocacionesServicioEspecialCache.locacionesServicioEspecial.ContainsKey(financiadorId))
                return;

            List<LocacionServicioEspecial> sucursalesPrestadorList = LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId];

            cacheReaderWriterLock.UpgradeToWriterLock(Timeout.Infinite);
            sucursalesPrestadorList.Remove(sucursalPrestador);
            LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId] = sucursalesPrestadorList;

            cacheReaderWriterLock.ReleaseLock();
        }

        public static void UpdateLocacionServicioEspecialToCache(int financiadorId, LocacionServicioEspecial locacionServicioEspecial)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            if (!LocacionesServicioEspecialCache.locacionesServicioEspecial.ContainsKey(financiadorId))
                return;

            List<LocacionServicioEspecial> sucursalesPrestadorList = LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId];
            //TODO: terminar
        }

        public static List<LocacionServicioEspecial> GetLocacionesServicioEspecial(int financiadorId, int servicioEspecialId)
        {
            return LocacionesServicioEspecialCache.GetLocacionesServicioEspecial(financiadorId, null, servicioEspecialId);
        }

        public static List<LocacionServicioEspecial> GetLocacionesServicioEspecial(int financiadorId, int? departamentoId, int servicioEspecialId)
        {
            cacheReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (!LocacionesServicioEspecialCache.locacionesServicioEspecial.ContainsKey(financiadorId))
                    return new List<LocacionServicioEspecial>();

                var locacionesServicioEspecial = from locacionServicioEspecial in LocacionesServicioEspecialCache.locacionesServicioEspecial[financiadorId]
                                                 where (departamentoId == null || locacionServicioEspecial.departamentoId == departamentoId) && (locacionServicioEspecial.servicioEspecialId == servicioEspecialId)
                                                 select locacionServicioEspecial;


                return locacionesServicioEspecial.ToList();
            }
            finally
            {
                cacheReaderWriterLock.ReleaseReaderLock();
            }
        }
    }
}
